<!DOCTYPE HTML>
<!--
	Dimension by HTML5 UP
	html5up.net | @ajlkn
	Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
-->
<html>
 <head>
  <title>
   Dimension by HTML5 UP
  </title>
  <!-- <meta charset="utf-8" /> -->
  <!-- <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" /> -->
  <meta charset="utf-8"/>
  <meta content="width=device-width,initial-scale=1.0" name="viewport"/>
  <link href="../../assets/css/article.css" rel="stylesheet"/>
  <link href="https://cdn.bootcss.com/highlight.js/9.15.8/styles/github.min.css" rel="stylesheet"/>
  <noscript>
   <link href="../../assets/css/noscript.css" rel="stylesheet"/>
  </noscript>
 </head>
 <body>
  <div id="app">
  </div>
  <!-- built files will be auto injected -->
 </body>
 <body class="is-preload">
  <!-- Wrapper -->
  <div id="wrapper">
   <!-- Main -->
   <div id="main">
    <article id="article">
     <h1 id="mybatis31">
      MyBatis3源码解析（1）探索准备
     </h1>
     <hr/>
     <p>
      这是我参与2022首次更文挑战的第6天，活动详情查看：
      <a href="https://juejin.cn/post/7052884569032392740">
       2022首次更文挑战
      </a>
     </p>
     <h2 id="_1">
      简介
     </h2>
     <p>
      本篇文章将使用原生的JDBC方式操作数据库，然后在使用Mybatis提供的方式操作数据库，通过对比两部分的操作，大致得到Mybatis所做的主要工作，为接下来的源码解析做准备
     </p>
     <h2 id="_2">
      示例代码
     </h2>
     <p>
      完整的工程已放到GitHub上：https://github.com/lw1243925457/MybatisDemo/tree/master/example
     </p>
     <h3 id="jdbc">
      原生的JDBC操作数据库
     </h3>
     <p>
      我们简单是写一个连接数据库、创建表、插入、查询、关闭的示例，如下所示：
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">JdbcTest</span> <span class="p">{</span>

    <span class="nd">@Test</span>
    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">test</span><span class="p">()</span> <span class="p">{</span>
        <span class="n">Connection</span> <span class="n">conn</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
        <span class="n">Statement</span> <span class="n">stmt</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
        <span class="k">try</span> <span class="p">{</span>
            <span class="c1">// STEP 1: 连接数据库</span>
            <span class="c1">// JDBC driver name and database URL</span>
            <span class="n">String</span> <span class="n">JDBC_DRIVER</span> <span class="o">=</span> <span class="s">"org.h2.Driver"</span><span class="p">;</span>
            <span class="n">Class</span><span class="p">.</span><span class="na">forName</span><span class="p">(</span><span class="n">JDBC_DRIVER</span><span class="p">);</span>

            <span class="n">System</span><span class="p">.</span><span class="na">out</span><span class="p">.</span><span class="na">println</span><span class="p">(</span><span class="s">"Connecting to database..."</span><span class="p">);</span>
            <span class="n">String</span> <span class="n">DB_URL</span> <span class="o">=</span> <span class="s">"jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"</span><span class="p">;</span>
            <span class="c1">//  Database credentials</span>
            <span class="n">String</span> <span class="n">USER</span> <span class="o">=</span> <span class="s">"sa"</span><span class="p">;</span>
            <span class="n">String</span> <span class="n">PASS</span> <span class="o">=</span> <span class="s">""</span><span class="p">;</span>
            <span class="n">conn</span> <span class="o">=</span> <span class="n">DriverManager</span><span class="p">.</span><span class="na">getConnection</span><span class="p">(</span><span class="n">DB_URL</span><span class="p">,</span> <span class="n">USER</span><span class="p">,</span> <span class="n">PASS</span><span class="p">);</span>

            <span class="c1">//STEP 2: 设置参数，查询</span>
            <span class="n">System</span><span class="p">.</span><span class="na">out</span><span class="p">.</span><span class="na">println</span><span class="p">(</span><span class="s">"Creating table in given database..."</span><span class="p">);</span>
            <span class="n">stmt</span> <span class="o">=</span> <span class="n">conn</span><span class="p">.</span><span class="na">createStatement</span><span class="p">();</span>
            <span class="n">String</span> <span class="n">sql</span> <span class="o">=</span>  <span class="s">"CREATE TABLE   REGISTRATION "</span> <span class="o">+</span>
                    <span class="s">"(id INTEGER not NULL, "</span> <span class="o">+</span>
                    <span class="s">" first VARCHAR(255), "</span> <span class="o">+</span>
                    <span class="s">" last VARCHAR(255), "</span> <span class="o">+</span>
                    <span class="s">" age INTEGER, "</span> <span class="o">+</span>
                    <span class="s">" PRIMARY KEY ( id ))"</span><span class="p">;</span>
            <span class="n">stmt</span><span class="p">.</span><span class="na">executeUpdate</span><span class="p">(</span><span class="n">sql</span><span class="p">);</span>
            <span class="n">System</span><span class="p">.</span><span class="na">out</span><span class="p">.</span><span class="na">println</span><span class="p">(</span><span class="s">"Created table in given database..."</span><span class="p">);</span>

            <span class="c1">//STEP 4: 处理查询结果</span>
            <span class="n">String</span> <span class="n">insertSql</span> <span class="o">=</span> <span class="s">"insert into REGISTRATION (id, first, last, age) values (?, ?, ?, ?)"</span><span class="p">;</span>
            <span class="n">PreparedStatement</span> <span class="n">insertPreparedStatement</span> <span class="o">=</span> <span class="n">conn</span><span class="p">.</span><span class="na">prepareStatement</span><span class="p">(</span><span class="n">insertSql</span><span class="p">);</span>
            <span class="n">insertPreparedStatement</span><span class="p">.</span><span class="na">setInt</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
            <span class="n">insertPreparedStatement</span><span class="p">.</span><span class="na">setString</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="s">"1"</span><span class="p">);</span>
            <span class="n">insertPreparedStatement</span><span class="p">.</span><span class="na">setString</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="s">"1"</span><span class="p">);</span>
            <span class="n">insertPreparedStatement</span><span class="p">.</span><span class="na">setInt</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
            <span class="n">insertPreparedStatement</span><span class="p">.</span><span class="na">executeUpdate</span><span class="p">();</span>

            <span class="n">String</span> <span class="n">querySql</span> <span class="o">=</span> <span class="s">"select * from REGISTRATION"</span><span class="p">;</span>
            <span class="n">ResultSet</span> <span class="n">resultSet</span> <span class="o">=</span> <span class="n">stmt</span><span class="p">.</span><span class="na">executeQuery</span><span class="p">(</span><span class="n">querySql</span><span class="p">);</span>
            <span class="n">ResultSetMetaData</span> <span class="n">metaData</span> <span class="o">=</span> <span class="n">resultSet</span><span class="p">.</span><span class="na">getMetaData</span><span class="p">();</span>
            <span class="k">while</span> <span class="p">(</span><span class="n">resultSet</span><span class="p">.</span><span class="na">next</span><span class="p">())</span> <span class="p">{</span>
                <span class="n">Registration</span> <span class="n">registration</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Registration</span><span class="p">();</span>
                <span class="n">registration</span><span class="p">.</span><span class="na">setId</span><span class="p">(</span><span class="n">resultSet</span><span class="p">.</span><span class="na">getInt</span><span class="p">(</span><span class="n">metaData</span><span class="p">.</span><span class="na">getColumnName</span><span class="p">(</span><span class="mi">1</span><span class="p">)));</span>
                <span class="n">registration</span><span class="p">.</span><span class="na">setFirst</span><span class="p">(</span><span class="n">resultSet</span><span class="p">.</span><span class="na">getString</span><span class="p">(</span><span class="n">metaData</span><span class="p">.</span><span class="na">getColumnName</span><span class="p">(</span><span class="mi">2</span><span class="p">)));</span>
                <span class="n">registration</span><span class="p">.</span><span class="na">setLast</span><span class="p">(</span><span class="n">resultSet</span><span class="p">.</span><span class="na">getString</span><span class="p">(</span><span class="n">metaData</span><span class="p">.</span><span class="na">getColumnName</span><span class="p">(</span><span class="mi">3</span><span class="p">)));</span>
                <span class="n">registration</span><span class="p">.</span><span class="na">setAge</span><span class="p">(</span><span class="n">resultSet</span><span class="p">.</span><span class="na">getInt</span><span class="p">(</span><span class="n">metaData</span><span class="p">.</span><span class="na">getColumnName</span><span class="p">(</span><span class="mi">4</span><span class="p">)));</span>
                <span class="n">System</span><span class="p">.</span><span class="na">out</span><span class="p">.</span><span class="na">println</span><span class="p">(</span><span class="n">registration</span><span class="p">);</span>
            <span class="p">}</span>

            <span class="c1">// STEP 4: 关闭连接</span>
            <span class="n">stmt</span><span class="p">.</span><span class="na">close</span><span class="p">();</span>
            <span class="n">conn</span><span class="p">.</span><span class="na">close</span><span class="p">();</span>
        <span class="p">}</span> <span class="k">catch</span><span class="p">(</span><span class="n">Exception</span> <span class="n">se</span><span class="p">)</span> <span class="p">{</span>
        <span class="p">......</span>
        <span class="p">}</span> <span class="c1">//end try</span>
        <span class="n">System</span><span class="p">.</span><span class="na">out</span><span class="p">.</span><span class="na">println</span><span class="p">(</span><span class="s">"Goodbye!"</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="nd">@Data</span>
    <span class="kd">static</span> <span class="kd">class</span> <span class="nc">Registration</span> <span class="p">{</span>
        <span class="kd">private</span> <span class="kt">int</span> <span class="n">id</span><span class="p">;</span>
        <span class="kd">private</span> <span class="n">String</span> <span class="n">first</span><span class="p">;</span>
        <span class="kd">private</span> <span class="n">String</span> <span class="n">last</span><span class="p">;</span>
        <span class="kd">private</span> <span class="kt">int</span> <span class="n">age</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <p>
      如上代码所示，核心的步骤如下：
     </p>
     <ul>
      <li>
       1.连接数据库
      </li>
      <li>
       2.查询，设置参数
      </li>
      <li>
       3.得到查询结果，转成我们想要的对象
      </li>
      <li>
       4.关闭连接
      </li>
     </ul>
     <p>
      1和4看着还好，但2和3，如果要硬是这样写的话，那代码可以感受很大的重复性，写很多的这样的代码就是一种折磨吧，哈哈
     </p>
     <h3 id="mybatis">
      MyBatis操作数据库示例
     </h3>
     <p>
      下面我们来看看Mybatis3是如果操作的，示例代码如下：
     </p>
     <p>
      为了简单，没有采用配置文件等方式，我们直接使用java代码的方式进行简单的配置
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">MybatisTest</span> <span class="p">{</span>

    <span class="nd">@Test</span>
    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">test</span><span class="p">()</span> <span class="p">{</span>
    <span class="c1">// 得到数据库链接</span>
        <span class="k">try</span><span class="p">(</span><span class="n">SqlSession</span> <span class="n">session</span> <span class="o">=</span> <span class="n">buildSqlSessionFactory</span><span class="p">().</span><span class="na">openSession</span><span class="p">())</span> <span class="p">{</span>
            <span class="n">PersonMapper</span> <span class="n">personMapper</span> <span class="o">=</span> <span class="n">session</span><span class="p">.</span><span class="na">getMapper</span><span class="p">(</span><span class="n">PersonMapper</span><span class="p">.</span><span class="na">class</span><span class="p">);</span>
        <span class="c1">// 创建表</span>
            <span class="n">personMapper</span><span class="p">.</span><span class="na">createTable</span><span class="p">();</span>
        <span class="c1">// 插入数据</span>
            <span class="n">personMapper</span><span class="p">.</span><span class="na">save</span><span class="p">(</span><span class="n">Person</span><span class="p">.</span><span class="na">builder</span><span class="p">().</span><span class="na">id</span><span class="p">(</span><span class="mi">1L</span><span class="p">).</span><span class="na">name</span><span class="p">(</span><span class="s">"1"</span><span class="p">).</span><span class="na">build</span><span class="p">());</span>
        <span class="c1">// 查询数据</span>
            <span class="n">Person</span> <span class="n">person</span> <span class="o">=</span> <span class="n">personMapper</span><span class="p">.</span><span class="na">getPersonById</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
            <span class="n">System</span><span class="p">.</span><span class="na">out</span><span class="p">.</span><span class="na">println</span><span class="p">(</span><span class="n">person</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="c1">// 构建数据库的连接信息和配置Mapper</span>
    <span class="kd">public</span> <span class="kd">static</span> <span class="n">SqlSessionFactory</span> <span class="nf">buildSqlSessionFactory</span><span class="p">()</span> <span class="p">{</span>
        <span class="n">String</span> <span class="n">JDBC_DRIVER</span> <span class="o">=</span> <span class="s">"org.h2.Driver"</span><span class="p">;</span>
        <span class="n">String</span> <span class="n">DB_URL</span> <span class="o">=</span> <span class="s">"jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"</span><span class="p">;</span>
        <span class="n">String</span> <span class="n">USER</span> <span class="o">=</span> <span class="s">"sa"</span><span class="p">;</span>
        <span class="n">String</span> <span class="n">PASS</span> <span class="o">=</span> <span class="s">""</span><span class="p">;</span>
        <span class="n">DataSource</span> <span class="n">dataSource</span> <span class="o">=</span> <span class="k">new</span> <span class="n">PooledDataSource</span><span class="p">(</span><span class="n">JDBC_DRIVER</span><span class="p">,</span> <span class="n">DB_URL</span><span class="p">,</span> <span class="n">USER</span><span class="p">,</span> <span class="n">PASS</span><span class="p">);</span>
        <span class="n">Environment</span> <span class="n">environment</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Environment</span><span class="p">(</span><span class="s">"Development"</span><span class="p">,</span> <span class="k">new</span> <span class="n">JdbcTransactionFactory</span><span class="p">(),</span> <span class="n">dataSource</span><span class="p">);</span>
        <span class="n">Configuration</span> <span class="n">configuration</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Configuration</span><span class="p">(</span><span class="n">environment</span><span class="p">);</span>
        <span class="n">configuration</span><span class="p">.</span><span class="na">addMapper</span><span class="p">(</span><span class="n">PersonMapper</span><span class="p">.</span><span class="na">class</span><span class="p">);</span>
        <span class="n">SqlSessionFactoryBuilder</span> <span class="n">builder</span> <span class="o">=</span> <span class="k">new</span> <span class="n">SqlSessionFactoryBuilder</span><span class="p">();</span>
        <span class="k">return</span> <span class="n">builder</span><span class="p">.</span><span class="na">build</span><span class="p">(</span><span class="n">configuration</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="kd">public</span> <span class="kd">interface</span> <span class="nc">PersonMapper</span> <span class="p">{</span>

    <span class="nd">@Insert</span><span class="p">(</span><span class="s">"create table person(id int not null, name varchar(255))"</span><span class="p">)</span>
    <span class="n">Integer</span> <span class="nf">createTable</span><span class="p">();</span>

    <span class="nd">@Insert</span><span class="p">(</span><span class="s">"Insert into person(id, name) values (#{id}, #{name})"</span><span class="p">)</span>
    <span class="n">Integer</span> <span class="nf">save</span><span class="p">(</span><span class="n">Person</span> <span class="n">person</span><span class="p">);</span>

    <span class="nd">@Select</span><span class="p">(</span><span class="s">"Select id, name from Person where id=#{id}"</span><span class="p">)</span>
    <span class="nd">@Results</span><span class="p">(</span><span class="n">value</span> <span class="o">=</span> <span class="p">{</span>
            <span class="nd">@Result</span><span class="p">(</span><span class="n">property</span> <span class="o">=</span> <span class="s">"id"</span><span class="p">,</span> <span class="n">column</span> <span class="o">=</span> <span class="s">"id"</span><span class="p">),</span>
            <span class="nd">@Result</span><span class="p">(</span><span class="n">property</span><span class="o">=</span><span class="s">"name"</span><span class="p">,</span> <span class="n">column</span> <span class="o">=</span> <span class="s">"name"</span><span class="p">),</span>
    <span class="p">})</span>
    <span class="n">Person</span> <span class="nf">getPersonById</span><span class="p">(</span><span class="n">Integer</span> <span class="n">personId</span><span class="p">);</span>
<span class="p">}</span>
</code></pre>
     </div>
     <p>
      如上，我们可以看到代码量相比直接操作数据库少了很多，而且可读性也比直接操作数据库好
     </p>
     <p>
      最大的简化点在：
     </p>
     <ol>
      <li>
       <p>
        自动构建设置了查询相关的参数，语义清晰，如示例中查询表明根据Id查询
       </p>
      </li>
      <li>
       <p>
        自动映射转换结果成我们定义的业务对象，大大简化了操作
       </p>
      </li>
     </ol>
     <h2 id="_3">
      总结
     </h2>
     <p>
      从上面的示例代码中，我们大致感受到了MyBatis所做的主要工作，所以我们解析的源码分析工作会从下面的方面展开：
     </p>
     <ul>
      <li>
       1.Mybatis的数据库连接
      </li>
      <li>
       2.Mybatis的查询
      </li>
      <li>
       3.Mybatis的结果映射
      </li>
     </ul>
    </article>
   </div>
   <!-- Footer -->
   <footer id="footer">
    <p class="copyright">
     © Untitled. Design:
     <a href="https://html5up.net">
      HTML5 UP
     </a>
     .
    </p>
   </footer>
  </div>
  <!-- BG -->
  <div id="bg">
  </div>
  <!-- Scripts -->
  <script src="../assets/js/jquery.min.js">
  </script>
  <script src="../assets/js/browser.min.js">
  </script>
  <script src="../assets/js/breakpoints.min.js">
  </script>
  <script src="../assets/js/util.js">
  </script>
  <script src="../assets/js/main.js">
  </script>
 </body>
</html>
